package com.imooc.pan.storage.engine.core;

import cn.hutool.core.lang.Assert;
import com.imooc.pan.storage.engine.core.context.DeleteFileContext;
import com.imooc.pan.storage.engine.core.context.MergeFileContext;
import com.imooc.pan.storage.engine.core.context.StoreFileChunkContext;
import com.imooc.pan.storage.engine.core.context.StoreFileContext;
import com.imooc.pan.web.cache.core.constants.CacheConstants;
import com.imooc.pan.web.core.exception.RPanFrameworkException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;

import java.io.IOException;
import java.util.Objects;

/**
 * @Description: /**
 * * 文件存储引擎模块公用抽象类
 * * 具体的文件存储实现方案的公用逻辑需要抽离到该类中
 * @Author: 张广焱
 * @Date: 2024-11-07 17:22
 */
public abstract class AbstractStorageEngine implements StorageEngine {


    @Autowired
    private CacheManager cacheManager;

    /**
     * @Description: 公用获取缓存的方法
     * @Author: 张广焱
     * @Date: 2024-11-07  17:26:21
     */
    protected Cache getCache() {
        if (Objects.isNull(cacheManager)) {
            throw new RPanFrameworkException("具体的缓存实现需要引用到项目中");
        }
        return cacheManager.getCache(CacheConstants.R_PAN_CACHE_NAME);
    }

    /**
     * @Description: 删除物理文件
     * 1.参数校验
     * 2.执行动作
     * @Author: 张广焱
     * @Date: 2024-11-08  14:14:45
     */
    @Override
    public void delete(DeleteFileContext context) throws IOException {
        checkDeleteFileContext(context);
        doDelete(context);
    }

    protected abstract void doDelete(DeleteFileContext context) throws IOException;



    /**
     * @Description: 校验删除物理文件的上下文信息
     * @Author: 张广焱
     * @Date: 2024-11-08  14:22:16
     */
    private void checkDeleteFileContext(DeleteFileContext context) {
        Assert.notEmpty(context.getRealFilePathList(), "要删除的文件路径列表不能为空");
    }

    /**
     * @Description: 存储物理文件
     * 1.参数校验
     * 2.执行动作
     * @Author: 张广焱
     * @Date: 2024-11-08  14:15:05
     */
    @Override
    public void store(StoreFileContext context) throws IOException {
        checkStoreFileContext(context);
        doStore(context);
    }

    /**
     * @Description: 校验上传物理文件的上下文信息
     * @Author: 张广焱
     * @Date: 2024-11-08  14:17:13
     */
    protected abstract void doStore(StoreFileContext context) throws IOException;


    /**
     * @Description:    存储物理文件的分片
     *     <p>
     *     1、参数校验
     *     2、执行动作
     * @Author: 张广焱
     * @Date: 2024-11-11  17:10:04
     */
    @Override
    public void storeChunk(StoreFileChunkContext context) throws IOException {
        checkStoreFileChunkContext(context);
        doStoreChunk(context);
    }

    /**
     * @param context
     * @Description: 校验保存文件分片的参数
     * @Author: 张广焱
     * @Date: 2024-11-11  17:11:30
     */
    private void checkStoreFileChunkContext(StoreFileChunkContext context) {
        Assert.notBlank(context.getFilename(), "文件名称不能为空");
        Assert.notBlank(context.getIdentifier(), "文件唯一标识不能为空");
        Assert.notNull(context.getTotalSize(), "文件大小不能为空");
        Assert.notNull(context.getInputStream(), "文件分片不能为空");
        Assert.notNull(context.getTotalChunks(), "文件分片总数不能为空");
        Assert.notNull(context.getChunkNumber(), "文件分片下标不能为空");
        Assert.notNull(context.getCurrentChunkSize(), "文件分片的大小不能为空");
        Assert.notNull(context.getUserId(), "当前登录用户的ID不能为空");
    }


    /**
     * @param context
     * @Description:    执行保存文件分片
     *       下沉到底层去实现
     * @Author: 张广焱
     * @Date: 2024-11-11  17:11:57
     */
    protected abstract void doStoreChunk(StoreFileChunkContext context) throws IOException;

    /**
     * @Description: 执行保存物理文件的动作
     * 下沉到具体的子类去实现
     * @Author: 张广焱
     * @Date: 2024-11-08  14:17:06
     */
    private void checkStoreFileContext(StoreFileContext context) {
        Assert.notBlank(context.getFilename(), "文件名称不能为空");
        Assert.notNull(context.getTotalSize(), "文件的总大小不能为空");
        Assert.notNull(context.getInputStream(), "文件不能为空");
    }

    /**
     * @param mergeFileContext
     * @Description:  1、检查参数
     *       2、执行动作
     * @Author: 张广焱
     * @Date: 2024-11-13  15:54:07
     */
    @Override
    public void mergeFile(MergeFileContext mergeFileContext) throws IOException {
        checkMergeFileContext(mergeFileContext);
        doMergeFile(mergeFileContext);
    }
    protected abstract void doMergeFile(MergeFileContext context) throws IOException;

    /**
     * 检查文件分片合并的上线文实体信息
     *
     * @param context
     */
    private void checkMergeFileContext(MergeFileContext context) {
        Assert.notBlank(context.getFilename(), "文件名称不能为空");
        Assert.notBlank(context.getIdentifier(), "文件唯一标识不能为空");
        Assert.notNull(context.getUserId(), "当前登录用户的ID不能为空");
        Assert.notEmpty(context.getRealPathList(), "文件分片列表不能为空");
    }
}
